package cat.sun.logic;

import android.os.Bundle;
import cat.sun.activities.Game.State;
import cat.sun.data.CellContent;
import cat.sun.data.CellState;
import cat.sun.listeners.BombChangeListener;
import cat.sun.listeners.ResultListener;


public class GameManager 
{
	private int moves;
	private int cellsCount,bombsCount;
	private int checkedBombs,checkedNotBombs;
	private int openedCells;
	private Pole pole;
	private long statredTime,pausedTime,EndedTime,ResultTime,pausedTimeAll;
	private BombChangeListener bombChangeListener;
	private ResultListener resultListener;
	private boolean isgameend;
	
	private Object synhro = new Object(); 
	
	
	public GameManager(int width,int height,int bombs,BombChangeListener bombChangeListener,ResultListener resultListener)
	{		
		cellsCount = width * height;
		bombsCount = bombs;
		this.bombChangeListener = bombChangeListener;
		this.resultListener = resultListener;
		this.pole = new Pole(height,width);
		
		moves = 0;
		checkedBombs = 0;
		checkedNotBombs = 0;	
		openedCells = 0;
		pausedTimeAll = 0;
		statredTime = 0;
		pausedTime = 0;
		EndedTime = 0;
		ResultTime = 0;
		this.isgameend = false;
		this.bombChangeListener.onBombsChangeed(checkedBombs + checkedNotBombs, bombsCount);
	}
	
	public void MakeMove(int x, int y,boolean movesinc)
	{	
		synchronized (synhro) 
		{
			if (isgameend) return;
			if (y >= pole.getHeight() || x >= pole.getWidth())
				return;

			if (movesinc)
				moves++;
			if (moves == 1 && movesinc) {
				pole.GenerateBombs(bombsCount, x, y);
				resultListener.onStarted();
			}
			CellContent cell;
			CellState state = pole.getCell(x, y).getState();
			if (state != CellState.OPEN)
				cell = pole.makeMove(x, y);
			else {
				synhro.notifyAll();
				return;
			}
			openedCells++;
			if (state == CellState.CHECKED) {
				if (cell == CellContent.BOMB)
					checkedBombs--;
				else
					checkedNotBombs--;
				bombChangeListener.onBombsChangeed(checkedBombs
						+ checkedNotBombs, bombsCount);
			}
			if (cell == CellContent.BOMB) {
				resultListener.onLose();
				this.pole.setRedBomb(x, y);
				this.pole.CrossAllBadFlags();
				this.pole.OpenAllBombs();
				synhro.notifyAll();
				return;
			}
			if (cell == CellContent.NOTHING) {
				for (int i = 0; i < 2; i++) {
					StartCircleOpening(0, 0);
					StartCircleOpening(0, pole.getHeight() - 1);
					StartCircleOpening(pole.getWidth() - 1,
							pole.getHeight() - 1);
					StartCircleOpening(pole.getWidth() - 1, 0);
				}
			}
			if (openedCells + bombsCount == cellsCount) {
				resultListener.onWin();
				this.pole.CheckAllBombs();
				this.checkedBombs = bombsCount;
				this.checkedNotBombs = 0;
				bombChangeListener.onBombsChangeed(checkedBombs
						+ checkedNotBombs, bombsCount);
			}
			synhro.notifyAll();
		}		
	}
	
	public Pole getFiled()
	{
		return this.pole;
	}
	
	public void getSaveBundle(Bundle save)
	{
		 save.putInt("Width", pole.getWidth());
		 save.putInt("Height", pole.getHeight());
		 save.putInt("Moves", moves);
		 save.putInt("CheckedBombs", checkedBombs);
		 save.putInt("CheckedNotBombs", checkedNotBombs);
		 save.putInt("OpenedCells", openedCells);
		 save.putLong("StatredTime", statredTime);
		 save.putLong("PausedTime", pausedTime);
		 save.putLong("EndedTime", EndedTime);
		 save.putLong("ResultTime", ResultTime);
		 save.putLong("PausedTimeAll", pausedTimeAll);
		 save.putBoolean("gameended", this.isgameend);
		 
		 int [] mas = new int[pole.getWidth()* pole.getHeight()*3];
		 int k = 0;
		 for (int i = 0;i< pole.getHeight();i++)
			 for(int j = 0;j<pole.getWidth();j++)
			 {
				 switch (pole.getCell(j, i).getCellContent())
				 {
				 case BOMB:mas[k] = 0;break;
				 case NOTHING:mas[k] = 1;break;
				 case NUMBER:mas[k] = 2;break;
				 case RED_BOMB:mas[k]=3;break;
				 }
				 k++;
				 switch (pole.getCell(j, i).getState())
				 {
				 case CHECKED:mas[k] = 0;break;
				 case CLOSE:mas[k] = 1;break;
				 case OPEN:mas[k] = 2;break;
				 case CROSS_CHECKED:mas[k] = 3;break;
				 }
				 k++;
				 mas[k] = pole.getCell(j, i).getNumber();
				 k++;
			 }
		 save.putIntArray("Cells", mas); 
	}	
	
	public void setSavedState(Bundle saved)
	{
		this.moves = saved.getInt("Moves");
		checkedBombs=saved.getInt("CheckedBombs");
		checkedNotBombs=saved.getInt("CheckedNotBombs");
		openedCells=saved.getInt("OpenedCells");
		statredTime=saved.getLong("StatredTime");
		pausedTime=saved.getLong("PausedTime");
		EndedTime=saved.getLong("EndedTime");
		ResultTime=saved.getLong("ResultTime");
		pausedTimeAll=saved.getLong("PausedTimeAll");
		this.isgameend = saved.getBoolean("gameended");
		int width = saved.getInt("Width");
		int height = saved.getInt("Height");
		this.bombChangeListener.onBombsChangeed(checkedBombs + checkedNotBombs, bombsCount);
		int [] mas = saved.getIntArray("Cells");
		int k=0;
		for (int i = 0;i<height;i++)
			 for(int j = 0;j<width;j++)
			 {
				 int cont = mas[k];
				 k++;
				 int state = mas[k];
				 k++;
				 int numb = mas[k];
				 k++;
				 switch (cont)
				 {
				 case 0:pole.getCell(j, i).makeBomb(); break;
				 case 1:;break;
				 case 2:pole.getCell(j, i).makeNumber(numb);break;
				 case 3:pole.getCell(j, i).setRedBomb();break;
				 }
				 switch (state)
				 {
				 case 0:pole.getCell(j, i).Checked();break;
				 case 1:;break;
				 case 2:pole.getCell(j, i).OpenCell();break;
				 case 3:pole.getCell(j, i).CrossCheck();break;
				 }
			 }
	}
	
	public void StartCircleOpening(int x,int y)
	{
		for (int i = 0;i<Math.max(pole.getWidth(), pole.getHeight());i++)
		{
			if (isOnField(0,y-i-1))
			for (int j = Math.max(x - i,0);j<=Math.min(x+i,pole.getWidth()-1);j++)
			{
				if (isOnField(j, y-i-1) && pole.getCell(j, y-i-1).getState() != CellState.OPEN) OpenCellIfNearIsNothing(j, y-i-1);
			}
			if (isOnField(0,y+i+1))
			for (int j = Math.max(x - i,0);j<=Math.min(x+i,pole.getWidth()-1);j++)
			{
				if (isOnField(j, y+i+1) && pole.getCell(j, y+i+1).getState() != CellState.OPEN) OpenCellIfNearIsNothing(j, y+i+1);
			}
			if (isOnField(x - i - 1,0))
			for (int j = Math.max(y - i - 1,0);j<=Math.min(y + i + 1,pole.getHeight()-1);j++)
			{
				if (isOnField(x - i - 1,j) && pole.getCell(x - i - 1,j).getState() != CellState.OPEN) OpenCellIfNearIsNothing(x - i - 1,j);
			}	
			if (isOnField(x + i + 1,0))
			for (int j = Math.max(y - i - 1,0);j<=Math.min(y + i + 1,pole.getHeight()-1);j++)
			{
				if (isOnField(x + i + 1,j) && pole.getCell(x + i + 1,j).getState() != CellState.OPEN) OpenCellIfNearIsNothing(x + i + 1,j);
			}	
		}
	}
	
	public void OpenCellIfNearIsNothing(int xx,int yy)
	{
		if (isOnField(xx - 1, yy + 1) && pole.getCell(xx - 1,  yy + 1).getState() == CellState.OPEN && pole.getCell(xx - 1,  yy + 1).getCellContent() == CellContent.NOTHING) OpenCell(xx, yy);
		else
		if (isOnField(xx , yy + 1) && pole.getCell(xx ,  yy + 1).getState() == CellState.OPEN && pole.getCell(xx,  yy + 1).getCellContent() == CellContent.NOTHING) OpenCell(xx , yy );
		else
		if (isOnField(xx + 1, yy + 1) && pole.getCell(xx + 1,  yy + 1).getState() == CellState.OPEN && pole.getCell(xx + 1,  yy + 1).getCellContent() == CellContent.NOTHING) OpenCell(xx , yy);
		else
		if (isOnField(xx - 1, yy) && pole.getCell(xx - 1,  yy ).getState() == CellState.OPEN && pole.getCell(xx - 1,  yy ).getCellContent() == CellContent.NOTHING) OpenCell(xx , yy );
		else
		if (isOnField(xx + 1, yy) && pole.getCell(xx + 1,  yy).getState() == CellState.OPEN && pole.getCell(xx + 1,  yy ).getCellContent() == CellContent.NOTHING) OpenCell(xx , yy );
		else
		if (isOnField(xx - 1, yy - 1) && pole.getCell(xx - 1,  yy - 1).getState() == CellState.OPEN && pole.getCell(xx - 1,  yy - 1).getCellContent() == CellContent.NOTHING) OpenCell(xx, yy);
		else
		if (isOnField(xx , yy - 1) && pole.getCell(xx ,  yy - 1).getState() == CellState.OPEN && pole.getCell(xx ,  yy - 1).getCellContent() == CellContent.NOTHING) OpenCell(xx , yy );
		else
		if (isOnField(xx + 1, yy - 1) && pole.getCell(xx + 1,  yy - 1).getState() == CellState.OPEN && pole.getCell(xx + 1,  yy - 1).getCellContent() == CellContent.NOTHING) OpenCell(xx , yy );
	}
	
	public void OpenCell(int x,int y)
	{
		CellState state = pole.getCell(x, y).getState();
		pole.makeMove(x, y);		
		openedCells++;
		if (state == CellState.CHECKED)
		{
			checkedNotBombs--;
			bombChangeListener.onBombsChangeed(checkedBombs + checkedNotBombs, bombsCount);
		}
	}
	
	public boolean isOnField(int x, int y)
	{
		if (x>=0 &&x<pole.getWidth() && y>=0 && y<pole.getHeight()) return true;
		return false;
	}	
	
	public void DoubleTouch(int x,int y)
	{
		synchronized (synhro) {
			if (isgameend || moves < 1) return;
			if (y >= pole.getHeight() || x >= pole.getWidth())
				return;
			if (!(pole.getCell(x, y).getState() == CellState.OPEN && pole
					.getCell(x, y).getCellContent() == CellContent.NUMBER))
				return;
			int ch_bombs = 0;
			int xx = x, yy = y;
			if (isOnField(xx - 1, yy + 1)
					&& pole.getCell(xx - 1, yy + 1).getState() == CellState.CHECKED)
				ch_bombs++;
			if (isOnField(xx, yy + 1)
					&& pole.getCell(xx, yy + 1).getState() == CellState.CHECKED)
				ch_bombs++;
			if (isOnField(xx + 1, yy + 1)
					&& pole.getCell(xx + 1, yy + 1).getState() == CellState.CHECKED)
				ch_bombs++;
			if (isOnField(xx - 1, yy)
					&& pole.getCell(xx - 1, yy).getState() == CellState.CHECKED)
				ch_bombs++;
			if (isOnField(xx + 1, yy)
					&& pole.getCell(xx + 1, yy).getState() == CellState.CHECKED)
				ch_bombs++;
			if (isOnField(xx - 1, yy - 1)
					&& pole.getCell(xx - 1, yy - 1).getState() == CellState.CHECKED)
				ch_bombs++;
			if (isOnField(xx, yy - 1)
					&& pole.getCell(xx, yy - 1).getState() == CellState.CHECKED)
				ch_bombs++;
			if (isOnField(xx + 1, yy - 1)
					&& pole.getCell(xx + 1, yy - 1).getState() == CellState.CHECKED)
				ch_bombs++;

			if (pole.getCell(x, y).getNumber() != ch_bombs)
				return;
			if (isOnField(xx - 1, yy + 1)
					&& pole.getCell(xx - 1, yy + 1).getState() == CellState.CLOSE)
				MakeMove(xx - 1, yy + 1, false);
			if (isOnField(xx, yy + 1)
					&& pole.getCell(xx, yy + 1).getState() == CellState.CLOSE)
				MakeMove(xx, yy + 1, false);
			if (isOnField(xx + 1, yy + 1)
					&& pole.getCell(xx + 1, yy + 1).getState() == CellState.CLOSE)
				MakeMove(xx + 1, yy + 1, false);
			if (isOnField(xx - 1, yy)
					&& pole.getCell(xx - 1, yy).getState() == CellState.CLOSE)
				MakeMove(xx - 1, yy, false);
			if (isOnField(xx + 1, yy)
					&& pole.getCell(xx + 1, yy).getState() == CellState.CLOSE)
				MakeMove(xx + 1, yy, false);
			if (isOnField(xx - 1, yy - 1)
					&& pole.getCell(xx - 1, yy - 1).getState() == CellState.CLOSE)
				MakeMove(xx - 1, yy - 1, false);
			if (isOnField(xx, yy - 1)
					&& pole.getCell(xx, yy - 1).getState() == CellState.CLOSE)
				MakeMove(xx, yy - 1, false);
			if (isOnField(xx + 1, yy - 1)
					&& pole.getCell(xx + 1, yy - 1).getState() == CellState.CLOSE)
				MakeMove(xx + 1, yy - 1, false);

			synhro.notifyAll();
		}		
	}
	
	public void Checked(int x, int y)
	{
		synchronized (synhro) 
		{		
			if (isgameend || moves < 1) return;
			if (y >= pole.getHeight() || x >= pole.getWidth())
				return;

			if (!(pole.getCell(x, y).getState() == CellState.OPEN)) 
			{
				if (pole.getCell(x, y).getCellContent() == CellContent.BOMB) 
				{
					if (pole.Check(x, y))
						checkedBombs++;
					else
						checkedBombs--;
				} else {
					if (pole.Check(x, y))
						checkedNotBombs++;
					else
						checkedNotBombs--;
				}
				bombChangeListener.onBombsChangeed(checkedBombs + checkedNotBombs, bombsCount);
			}
			synhro.notifyAll();
		}
	}

	public int getFlagsLeft()
	{
		return this.bombsCount - checkedBombs - checkedNotBombs;
	}
	
	public void startTime()
	{
		this.statredTime = System.currentTimeMillis();
	}
	
	public void PauseTime()
	{
		this.pausedTime = System.currentTimeMillis();
	}
	
	public void ResumeTime()
	{
		this.pausedTimeAll += System.currentTimeMillis() - this.pausedTime;
	}
	
	public void EndTime()
	{
		this.EndedTime = System.currentTimeMillis();
		this.ResultTime = this.EndedTime - this.statredTime - this.pausedTimeAll;
		this.isgameend = true;
	}
	
	public long resultedTime()
	{
		return this.ResultTime;
	}
	
	public long getCurrentTime(State state)
	{
		if (state == State.created) return 0l;
		if (state == State.endgame) return resultedTime();
		if (state == State.paused) return pausedTime - this.statredTime - this.pausedTimeAll;
		if (state == State.playing) return System.currentTimeMillis() - this.statredTime - this.pausedTimeAll;	
		return 0l;
	}
	
}
